home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / PROGS / EXAMPLES / DINODRAW.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  11.3 KB  |  421 lines

  1. /* 
  2.  * Dinodraw.c
  3.  *
  4.  * Copyright (c) James Bowman 1998,
  5.  * parts (c) Mark J. Kilgard, 1994.
  6.  */
  7.  
  8. /* This program is freely distributable without licensing fees 
  9.    and is provided without guarantee or warrantee expressed or 
  10.    implied. This program is -not- in the public domain. */
  11.  
  12. /* Modified version of Mark J. Kilgard's dinospin that demontrates use of
  13.  * stencil buffer to interactively view overdraw.
  14.  */
  15.  
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <math.h>       /* for cos(), sin(), and sqrt() */
  20. #include <GL/glut.h>
  21. #include "trackball.h"
  22.  
  23. typedef enum {
  24.   RESERVED, BODY_SIDE, BODY_EDGE, BODY_WHOLE, ARM_SIDE, ARM_EDGE, ARM_WHOLE,
  25.   LEG_SIDE, LEG_EDGE, LEG_WHOLE, EYE_SIDE, EYE_EDGE, EYE_WHOLE, DINOSAUR
  26. } displayLists;
  27.  
  28. GLfloat angle = -150;   /* in degrees */
  29. GLboolean doubleBuffer = GL_TRUE, iconic = GL_FALSE, keepAspect = GL_FALSE;
  30. int spinning = 0, moving = 0;
  31. int beginx, beginy;
  32. int W = 300, H = 300;
  33. float curquat[4];
  34. float lastquat[4];
  35. GLdouble bodyWidth = 2.0;
  36. int newModel = 1;
  37. int scaling;
  38. float scalefactor = 1.0;
  39. /* *INDENT-OFF* */
  40. GLfloat body[][2] = { {0, 3}, {1, 1}, {5, 1}, {8, 4}, {10, 4}, {11, 5},
  41.   {11, 11.5}, {13, 12}, {13, 13}, {10, 13.5}, {13, 14}, {13, 15}, {11, 16},
  42.   {8, 16}, {7, 15}, {7, 13}, {8, 12}, {7, 11}, {6, 6}, {4, 3}, {3, 2},
  43.   {1, 2} };
  44. GLfloat arm[][2] = { {8, 10}, {9, 9}, {10, 9}, {13, 8}, {14, 9}, {16, 9},
  45.   {15, 9.5}, {16, 10}, {15, 10}, {15.5, 11}, {14.5, 10}, {14, 11}, {14, 10},
  46.   {13, 9}, {11, 11}, {9, 11} };
  47. GLfloat leg[][2] = { {8, 6}, {8, 4}, {9, 3}, {9, 2}, {8, 1}, {8, 0.5}, {9, 0},
  48.   {12, 0}, {10, 1}, {10, 2}, {12, 4}, {11, 6}, {10, 7}, {9, 7} };
  49. GLfloat eye[][2] = { {8.75, 15}, {9, 14.7}, {9.6, 14.7}, {10.1, 15},
  50.   {9.6, 15.25}, {9, 15.25} };
  51. GLfloat lightZeroPosition[] = {10.0, 4.0, 10.0, 1.0};
  52. GLfloat lightZeroColor[] = {0.8, 1.0, 0.8, 1.0}; /* green-tinted */
  53. GLfloat lightOnePosition[] = {-1.0, -2.0, 1.0, 0.0};
  54. GLfloat lightOneColor[] = {0.6, 0.3, 0.2, 1.0}; /* red-tinted */
  55. GLfloat skinColor[] = {0.1, 1.0, 0.1, 1.0}, eyeColor[] = {1.0, 0.2, 0.2, 1.0};
  56. /* *INDENT-ON* */
  57.  
  58. void
  59. extrudeSolidFromPolygon(GLfloat data[][2], unsigned int dataSize,
  60.   GLdouble thickness, GLuint side, GLuint edge, GLuint whole)
  61. {
  62.   static GLUtriangulatorObj *tobj = NULL;
  63.   GLdouble vertex[3], dx, dy, len;
  64.   int i;
  65.   int count = dataSize / (2 * sizeof(GLfloat));
  66.  
  67.   if (tobj == NULL) {
  68.     tobj = gluNewTess();  /* create and initialize a GLU
  69.                              polygon * * tesselation object */
  70.     gluTessCallback(tobj, GLU_BEGIN, glBegin);
  71.     gluTessCallback(tobj, GLU_VERTEX, glVertex2fv);  /* semi-tricky 
  72.  
  73.                                                       */
  74.     gluTessCallback(tobj, GLU_END, glEnd);
  75.   }
  76.   glNewList(side, GL_COMPILE);
  77.   glShadeModel(GL_SMOOTH);  /* smooth minimizes seeing
  78.                                tessellation */
  79.   gluBeginPolygon(tobj);
  80.   for (i = 0; i < count; i++) {
  81.     vertex[0] = data[i][0];
  82.     vertex[1] = data[i][1];
  83.     vertex[2] = 0;
  84.     gluTessVertex(tobj, vertex, data[i]);
  85.   }
  86.   gluEndPolygon(tobj);
  87.   glEndList();
  88.   glNewList(edge, GL_COMPILE);
  89.   glShadeModel(GL_FLAT);  /* flat shade keeps angular hands
  90.                              from being * * "smoothed" */
  91.   glBegin(GL_QUAD_STRIP);
  92.   for (i = 0; i <= count; i++) {
  93.     /* mod function handles closing the edge */
  94.     glVertex3f(data[i % count][0], data[i % count][1], 0.0);
  95.     glVertex3f(data[i % count][0], data[i % count][1], thickness);
  96.     /* Calculate a unit normal by dividing by Euclidean
  97.        distance. We * could be lazy and use
  98.        glEnable(GL_NORMALIZE) so we could pass in * arbitrary
  99.        normals for a very slight performance hit. */
  100.     dx = data[(i + 1) % count][1] - data[i % count][1];
  101.     dy = data[i % count][0] - data[(i + 1) % count][0];
  102.     len = sqrt(dx * dx + dy * dy);
  103.     glNormal3f(dx / len, dy / len, 0.0);
  104.   }
  105.   glEnd();
  106.   glEndList();
  107.   glNewList(whole, GL_COMPILE);
  108.   glFrontFace(GL_CW);
  109.   glCallList(edge);
  110.   glNormal3f(0.0, 0.0, -1.0);  /* constant normal for side */
  111.   glCallList(side);
  112.   glPushMatrix();
  113.   glTranslatef(0.0, 0.0, thickness);
  114.   glFrontFace(GL_CCW);
  115.   glNormal3f(0.0, 0.0, 1.0);  /* opposite normal for other side 
  116.  
  117.                                */
  118.   glCallList(side);
  119.   glPopMatrix();
  120.   glEndList();
  121. }
  122.  
  123. void
  124. makeDinosaur(void)
  125. {
  126.   GLfloat bodyWidth = 3.0;
  127.  
  128.   extrudeSolidFromPolygon(body, sizeof(body), bodyWidth,
  129.     BODY_SIDE, BODY_EDGE, BODY_WHOLE);
  130.   extrudeSolidFromPolygon(arm, sizeof(arm), bodyWidth / 4,
  131.     ARM_SIDE, ARM_EDGE, ARM_WHOLE);
  132.   extrudeSolidFromPolygon(leg, sizeof(leg), bodyWidth / 2,
  133.     LEG_SIDE, LEG_EDGE, LEG_WHOLE);
  134.   extrudeSolidFromPolygon(eye, sizeof(eye), bodyWidth + 0.2,
  135.     EYE_SIDE, EYE_EDGE, EYE_WHOLE);
  136.   glNewList(DINOSAUR, GL_COMPILE);
  137.   glMaterialfv(GL_FRONT, GL_DIFFUSE, skinColor);
  138.   glCallList(BODY_WHOLE);
  139.   glPushMatrix();
  140.   glTranslatef(0.0, 0.0, bodyWidth);
  141.   glCallList(ARM_WHOLE);
  142.   glCallList(LEG_WHOLE);
  143.   glTranslatef(0.0, 0.0, -bodyWidth - bodyWidth / 4);
  144.   glCallList(ARM_WHOLE);
  145.   glTranslatef(0.0, 0.0, -bodyWidth / 4);
  146.   glCallList(LEG_WHOLE);
  147.   glTranslatef(0.0, 0.0, bodyWidth / 2 - 0.1);
  148.   glMaterialfv(GL_FRONT, GL_DIFFUSE, eyeColor);
  149.   glCallList(EYE_WHOLE);
  150.   glPopMatrix();
  151.   glEndList();
  152. }
  153.  
  154. void
  155. recalcModelView(void)
  156. {
  157.   GLfloat m[4][4];
  158.  
  159.   glPopMatrix();
  160.   glPushMatrix();
  161.   build_rotmatrix(m, curquat);
  162.   glMultMatrixf(&m[0][0]);
  163.   glScalef(scalefactor, scalefactor, scalefactor);
  164.   glTranslatef(-8, -8, -bodyWidth / 2);
  165.   newModel = 0;
  166. }
  167.  
  168. void
  169. showMessage(GLfloat x, GLfloat y, GLfloat z, char *message)
  170. {
  171.   glPushMatrix();
  172.   glDisable(GL_LIGHTING);
  173.   glTranslatef(x, y, z);
  174.   glScalef(.02, .02, .02);
  175.   while (*message) {
  176.     glutStrokeCharacter(GLUT_STROKE_ROMAN, *message);
  177.     message++;
  178.   }
  179.   glEnable(GL_LIGHTING);
  180.   glPopMatrix();
  181. }
  182.  
  183. void
  184. redraw(void)
  185. {
  186.   if (newModel)
  187.     recalcModelView();
  188.  
  189.   glClear(GL_COLOR_BUFFER_BIT | 
  190.       GL_DEPTH_BUFFER_BIT | 
  191.       GL_STENCIL_BUFFER_BIT);
  192.  
  193.   /* Draw the real scene in the left viewport... */
  194.   glViewport(0, 0, W / 2, H);
  195.  
  196.   glDisable(GL_STENCIL_TEST);
  197.   glCallList(DINOSAUR);
  198.   showMessage(2, 7.1, 4.1, "Spin me.");
  199.  
  200.   /* ...and the overdraw indicator in the right viewport */
  201.   glViewport(W / 2, 0, W / 2, H);
  202.  
  203.   /* First draw the scene again, this time without color updates,
  204.    * just counting pixels drawn in the stencil buffer.
  205.    */
  206.   glEnable(GL_STENCIL_TEST);
  207.   glStencilFunc(GL_ALWAYS, 0, 0);
  208.   glStencilOp(GL_KEEP, GL_INCR, GL_INCR);
  209.   glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  210.   glCallList(DINOSAUR);
  211.   showMessage(2, 7.1, 4.1, "Spin me.");
  212.  
  213.   glMatrixMode(GL_MODELVIEW);
  214.   glPushMatrix();
  215.   glLoadIdentity();
  216.   glMatrixMode(GL_PROJECTION);
  217.   glPushMatrix();
  218.   glLoadIdentity();
  219.   glDisable(GL_LIGHTING);
  220.   glDisable(GL_DEPTH_TEST);
  221.  
  222.   glColor3f(1.0f, 1.0f, 1.0f);
  223.   glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  224.  
  225.   /* Copy bit 0 into the blue plane */
  226.   glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_FALSE);
  227.   glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x01);
  228.   glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
  229.  
  230.   /* Copy bit 1 into the red plane */
  231.   glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
  232.   glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x02);
  233.   glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
  234.  
  235.   /* Copy bit 2 into the green plane */
  236.   glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_FALSE);
  237.   glStencilFunc(GL_NOTEQUAL, 0, 0xf8 | 0x04);
  238.   glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
  239.  
  240.   /* Note that anything greater than 7 will have one of  bits 3-7 set,
  241.    * hence will be drawn on all three planes by the mask with 0xf8 above.
  242.    * So anything overdrawn 7 or more times will be drawn in white.
  243.    */
  244.  
  245.   glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  246.   glEnable(GL_DEPTH_TEST);
  247.   glEnable(GL_LIGHTING);
  248.   glMatrixMode(GL_PROJECTION);
  249.   glPopMatrix();
  250.   glMatrixMode(GL_MODELVIEW);
  251.   glPopMatrix();
  252.  
  253.   glutSwapBuffers();
  254. }
  255.  
  256. void
  257. myReshape(int w, int h)
  258. {
  259.   glViewport(0, 0, w / 2, h);
  260.   W = w;
  261.   H = h;
  262. }
  263.  
  264. void
  265. mouse(int button, int state, int x, int y)
  266. {
  267.   if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
  268.     spinning = 0;
  269.     glutIdleFunc(NULL);
  270.     moving = 1;
  271.     beginx = x;
  272.     beginy = y;
  273.     if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) {
  274.       scaling = 1;
  275.     } else {
  276.       scaling = 0;
  277.     }
  278.   }
  279.   if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
  280.     moving = 0;
  281.   }
  282. }
  283.  
  284. void
  285. animate(void)
  286. {
  287.   add_quats(lastquat, curquat, curquat);
  288.   newModel = 1;
  289.   glutPostRedisplay();
  290. }
  291.  
  292. void
  293. motion(int x, int y)
  294. {
  295.   if (scaling) {
  296.     scalefactor = scalefactor * (1.0 + (((float) (beginy - y)) / H));
  297.     beginx = x;
  298.     beginy = y;
  299.     newModel = 1;
  300.     glutPostRedisplay();
  301.     return;
  302.   }
  303.   if (moving) {
  304.     trackball(lastquat,
  305.       (2.0 * beginx - W) / W,
  306.       (H - 2.0 * beginy) / H,
  307.       (2.0 * x - W) / W,
  308.       (H - 2.0 * y) / H
  309.       );
  310.     beginx = x;
  311.     beginy = y;
  312.     spinning = 1;
  313.     glutIdleFunc(animate);
  314.   }
  315. }
  316.  
  317. GLboolean lightZeroSwitch = GL_TRUE, lightOneSwitch = GL_TRUE;
  318.  
  319. void
  320. controlLights(int value)
  321. {
  322.   switch (value) {
  323.   case 1:
  324.     lightZeroSwitch = !lightZeroSwitch;
  325.     if (lightZeroSwitch) {
  326.       glEnable(GL_LIGHT0);
  327.     } else {
  328.       glDisable(GL_LIGHT0);
  329.     }
  330.     break;
  331.   case 2:
  332.     lightOneSwitch = !lightOneSwitch;
  333.     if (lightOneSwitch) {
  334.       glEnable(GL_LIGHT1);
  335.     } else {
  336.       glDisable(GL_LIGHT1);
  337.     }
  338.     break;
  339. #ifdef GL_MULTISAMPLE_SGIS
  340.   case 3:
  341.     if (glIsEnabled(GL_MULTISAMPLE_SGIS)) {
  342.       glDisable(GL_MULTISAMPLE_SGIS);
  343.     } else {
  344.       glEnable(GL_MULTISAMPLE_SGIS);
  345.     }
  346.     break;
  347. #endif
  348.   case 4:
  349.     glutFullScreen();
  350.     break;
  351.   case 5:
  352.     exit(0);
  353.     break;
  354.   }
  355.   glutPostRedisplay();
  356. }
  357.  
  358. void
  359. vis(int visible)
  360. {
  361.   if (visible == GLUT_VISIBLE) {
  362.     if (spinning)
  363.       glutIdleFunc(animate);
  364.   } else {
  365.     if (spinning)
  366.       glutIdleFunc(NULL);
  367.   }
  368. }
  369.  
  370. int
  371. main(int argc, char **argv)
  372. {
  373.   glutInit(&argc, argv);
  374.   glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
  375.   trackball(curquat, 0.0, 0.0, 0.0, 0.0);
  376.   glutInitWindowSize(600, 300);
  377.   glutCreateWindow("dinodraw");
  378.   glutDisplayFunc(redraw);
  379.   glutReshapeFunc(myReshape);
  380.   glutVisibilityFunc(vis);
  381.   glutMouseFunc(mouse);
  382.   glutMotionFunc(motion);
  383.   glutCreateMenu(controlLights);
  384.   glutAddMenuEntry("Toggle right light", 1);
  385.   glutAddMenuEntry("Toggle left light", 2);
  386.   if (glutGet(GLUT_WINDOW_NUM_SAMPLES) > 0) {
  387.     glutAddMenuEntry("Toggle multisampling", 3);
  388.     glutSetWindowTitle("dinospin (multisample capable)");
  389.   }
  390.   glutAddMenuEntry("Full screen", 4);
  391.   glutAddMenuEntry("Quit", 5);
  392.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  393.   makeDinosaur();
  394.   glEnable(GL_CULL_FACE);
  395.   glEnable(GL_DEPTH_TEST);
  396.   glEnable(GL_LIGHTING);
  397.   glMatrixMode(GL_PROJECTION);
  398.   gluPerspective( /* field of view in degree */ 40.0,
  399.   /* aspect ratio */ 1.0,
  400.     /* Z near */ 1.0, /* Z far */ 40.0);
  401.   glMatrixMode(GL_MODELVIEW);
  402.   gluLookAt(0.0, 0.0, 30.0,  /* eye is at (0,0,30) */
  403.     0.0, 0.0, 0.0,      /* center is at (0,0,0) */
  404.     0.0, 1.0, 0.);      /* up is in positive Y direction */
  405.   glPushMatrix();       /* dummy push so we can pop on model
  406.                            recalc */
  407.   glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
  408.   glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition);
  409.   glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor);
  410.   glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1);
  411.   glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05);
  412.   glLightfv(GL_LIGHT1, GL_POSITION, lightOnePosition);
  413.   glLightfv(GL_LIGHT1, GL_DIFFUSE, lightOneColor);
  414.   glEnable(GL_LIGHT0);
  415.   glEnable(GL_LIGHT1);
  416.   glLineWidth(2.0);
  417.   glutMainLoop();
  418.   return 0;             /* ANSI C requires main to return int. */
  419. }
  420.  
  421.